package key.w8.boot.service;


import key.w8.boot.annotation.K8Service;
import key.w8.boot.contenxt.ServiceContext;
import key.w8.boot.service.factoroyBean.ServiceFactoryFactoryBean;
import org.reflections.Reflections;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Author: k8
 * @CreateTime: 2025-07-27
 * @Version: 1.0
 */

public class ServiceRegistry implements BeanDefinitionRegistryPostProcessor, EnvironmentAware, BeanFactoryAware {
    private static String BASE_PACKAGE = "k8.rpc.config.base-package";
    private Environment env;
    private BeanFactory beanFactory;
    public ServiceRegistry() {

    }

    /**
     * 扫描指定包下所有标注了 @AS 的接口
     *
     * @return 所有标注了 @AS 的接口 Class 对象
     */

    private Set<Class<?>> scanServices() {
        String basepackage = env.getProperty(BASE_PACKAGE);
        Reflections reflections = new Reflections(basepackage);
        // 获取所有带有 @AiService 注解的接口
        return reflections.getTypesAnnotatedWith(K8Service.class)
                .stream()
                .filter(clazz->{
                    return !clazz.isInterface();
                })  // 确保是接口
                .collect(Collectors.toSet());
    }

    /**
     * service应该是扫描类，然后对所有接口进行暴露，但是不用FactoryBean，更适合的是扫描注解，然后注册一个ServiceFactory
     * @param registry
     * @throws BeansException
     */
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        Set<Class<?>> classes = scanServices();
        List<ServiceContext> serviceContexts = new LinkedList<>();
        for (Class<?> instanceClass : classes) {
            K8Service annotation = instanceClass.getAnnotation(K8Service.class);
            Object instance;
            try {
                Constructor<?> constructor = instanceClass.getConstructor();
                instance = constructor.newInstance();
            } catch (NoSuchMethodException | InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }

            Class<?>[] interfaces = instanceClass.getInterfaces();
            for (Class<?> anInterface : interfaces) {
                ServiceContext serviceContext = new ServiceContext();
                serviceContext.setVersion(annotation.version());
                serviceContext.setType((Class<Object>) anInterface);
                int[] ports = annotation.ports();
                Integer[] pports = new Integer[ports.length];
                int index = 0;
                for (int port : ports) {
                    pports[index++] = port;
                }
                serviceContext.setPorts(pports);
                serviceContext.setProtocols(Arrays.asList(annotation.protocols()));
                serviceContext.setGroup(annotation.group());
                serviceContext.setInstance(instance);
                serviceContexts.add(serviceContext);
            }
        }
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        // 关键：设置 FactoryBean，延迟生成代理对象
        beanDefinition.setBeanClassName(ServiceFactoryFactoryBean.class.getName());
        beanDefinition.setBeanClass(ServiceFactory.class);
        ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
        constructorArgumentValues.addGenericArgumentValue(serviceContexts);
        registry.registerBeanDefinition("serviceFactory", beanDefinition);
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.env = environment;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}